/**
* \file DGVTransform.h
*
* \brief This file defines the class that wraps all the transforms using threads.
* \author Shekhar S. Chandra, 2008-2009
*
* This file is part of DGV Library.
*
* DGV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DGV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DGV.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DGVTRANSFORM_H
#define DGVTRANSFORM_H

///Qt Constructs
#include "DGVImage.h" ///Also includes DGVTable.
#include "DGVConsole.h"

///Transform Includes
#include "DGVRadonTransform.h"
#include "DGVFourierTransform.h"

///Transform enum
enum transformType {None = 0, FFT, iFFT, FFT_Real, iFFT_Real, FFT_1D, iFFT_1D, FFT_Real_1D, iFFT_Real_1D,
                    FFT_1D_Batch, iFFT_1D_Batch, FFT_Real_1D_Batch, iFFT_Real_1D_Batch,
                    radonSlicing, radonSlicing_Real, FRT, iFRT, iFRT_Unscaled};

/**
 \class DGVTransform
 \brief Interface class that Binds all the transform classes together for usage with Qt constructs
 such as Images and Tables.

 This transform wrapper runs transforms (FFT etc.) in threads. \todo Multi-threading: Cannot handle multi-threading. Enforce "wait" until transform is complete.
 \author Shekhar S. Chandra, 2008-2009
*/
class DGV_EXPORT DGVTransform : public QThread
{
    Q_OBJECT

public:
    DGVTransform(QObject *parent = 0);
    virtual ~DGVTransform();

    /**
     \fn DGVTransform::setName(QString newName)
     \brief Name of the operation. Doesn't effect transforms only for users reference.
    */
    inline void setName(QString newName)
    {   name = newName; }
    /**
     \fn DGVTransform::getName()
     \brief Returns the name of the operation. The name doesn't effect transforms only for users reference.
    */
    inline QString getName()
    {   return name;    }

    /*! \name Discrete Radon Transforms */
	//@{
    /**
     \fn DGVTransform::frt(DGVImage *image)
     \brief Conducts the FRT of an image. Sends signal with resultant image. DISABLED
    */
    void frt(DGVImage *image);
    /**
     \fn DGVTransform::frt(Array<imageType,2> &image)
     \brief Conducts the FRT of an image. Sends signal with resultant image.
    */
    void frt(Array<imageType,2> &image);
    /**
     \fn DGVTransform::ifrt(DGVImage *bins)
     \brief Conducts the inverse FRT of an image. Sends signal with resultant image. DISABLED
    */
    void ifrt(DGVImage *bins);
    /**
     \fn DGVTransform::ifrt(Array<imageType,2> &bins)
     \brief Conducts the inverse FRT of an image. Sends signal with resultant image.
    */
    void ifrt(Array<imageType,2> &bins);
    /**
     \fn DGVTransform::ifrtUnscaled(DGVImage *image)
     \brief Conducts the inverse FRT of an image without dividing by p. Sends signal with resultant image. DISABLED
    */
    void ifrtUnscaled(DGVImage *image);
    /**
     \fn DGVTransform::ifrtUnscaled(Array<imageType,2> &bins)
     \brief Conducts the inverse FRT of an image without dividing by p. Sends signal with resultant image.
    */
    void ifrtUnscaled(Array<imageType,2> &bins);
    //@}

    /*! \name Constructors */
	//@{
    /**
     \fn DGVTransform::fft(Array<complex<imageType>,2> &image)
     \brief Conducts the FFT of an image. Sends signal with resultant image.
    */
    void fft(Array<complex<imageType>,2> &image);
    /**
     \fn DGVTransform::ifft(Array<complex<imageType>,2> &kSpace)
     \brief Conducts the inverse FFT of an image. Sends signal with resultant image.
    */
    void ifft(Array<complex<imageType>,2> &kSpace);
    /**
     \fn DGVTransform::fft_real(Array<imageType,2> &image)
     \brief Conducts the FFT of an image. Sends signal with resultant image.
    */
    void fft_real(Array<imageType,2> &image);
    /**
     \fn DGVTransform::ifft_real(Array<complex<imageType>,2> &kSpace)
     \brief Conducts the inverse FFT of an image. Sends signal with resultant image.
    */
    void ifft_real(Array<complex<imageType>,2> &kSpace);
    /**
     \fn DGVTransform::fft_1D(Array<complex<imageType>,1> &image)
     \brief Conducts the 1D FFT of an image. Sends signal with resultant image.
    */
    void fft_1D(Array<complex<imageType>,1> &image);
    /**
     \fn DGVTransform::fft_1D(Array<complex<imageType>,2> &image)
     \brief Conducts the 1D FFT of an image. Sends signal with resultant image. Not multi-threaded.
    */
    void fft_1D(Array<complex<imageType>,2> &image);
    /**
     \fn DGVTransform::ifft_1D(Array<complex<imageType>,1> &kSpace)
     \brief Conducts the inverse 1D FFT of an image. Sends signal with resultant image.
    */
    void ifft_1D(Array<complex<imageType>,1> &kSpace);
    /**
     \fn DGVTransform::ifft_1D(Array<complex<imageType>,2> &kSpace)
     \brief Conducts the inverse 1D FFT of an image. Sends signal with resultant image. Not multi-threaded.
    */
    void ifft_1D(Array<complex<imageType>,2> &kSpace);
    /**
     \fn DGVTransform::fft_real_1D(Array<imageType,1> &image)
     \brief Conducts the real 1D FFT of an image. Sends signal with resultant image.
    */
    void fft_real_1D(Array<imageType,1> &image);
    /**
     \fn DGVTransform::fft_real_1D(Array<imageType,2> &image)
     \brief Conducts the real 1D FFT of an image. Sends signal with resultant image. Not multi-threaded.
    */
    void fft_real_1D(Array<imageType,2> &image);
    /**
     \fn DGVTransform::ifft_real_1D(Array<complex<imageType>,1> &kSpace)
     \brief Conducts the real inverse 1D FFT of an image. Sends signal with resultant image.
    */
    void ifft_real_1D(Array<complex<imageType>,1> &kSpace);
    /**
     \fn DGVTransform::ifft_real_1D(Array<complex<imageType>,2> &kSpace)
     \brief Conducts the real inverse 1D FFT of an image. Sends signal with resultant image. Not multi-threaded.
    */
    void ifft_real_1D(Array<complex<imageType>,2> &kSpace);
    /**
     \fn DGVTransform::radonSlices(Array<complex<imageType>,2> &kSpace)
     \brief Extracts the Radon slices from an image. Sends signal with resultant image.
    */
    void radonSlices(Array<complex<imageType>,2> &kSpace);
    /**
     \fn DGVTransform::radonSlices(Array<imageType,2> &kSpace)
     \brief Extracts the Radon slices from an image. Sends signal with resultant image.
    */
    void radonSlices(Array<imageType,2> &kSpace);
    //@}

    /*! \name Options */
	//@{
    /**
     \fn DGVTransform::reset()
     \brief Reset internal transform information.
    */
    void reset();
    /**
     \fn DGVTransform::shiftDC(Array<imageType,2> &kSpace)
     \brief Shift the DC in in array.
    */
    inline void shiftDC(Array<imageType,2> &kSpace)
    {   kSpace = Fourier.shiftDC(kSpace);   }
    /**
     \fn DGVTransform::shiftDC(Array<complex<imageType>,2> &kSpace)
     \brief Shift the DC in in array.
    */
    inline void shiftDC(Array<complex<imageType>,2> &kSpace)
    {   kSpace = Fourier.shiftDC(kSpace);   }
    /**
     \fn DGVTransform::normalise(Array<imageType,2> &kSpace)
     \brief Normalise the array.
    */
    inline void normalise(Array<imageType,2> &kSpace)
    {   Fourier.normalise(kSpace);   }
    /**
     \fn DGVTransform::normalise(Array<complex<imageType>,2> &kSpace)
     \brief Normalise the array.
    */
    inline void normalise(Array<complex<imageType>,2> &kSpace)
    {   Fourier.normalise(kSpace);   }
    /**
     \fn DGVTransform::alwaysWaitTillComplete(bool waitTillComplete)
     \brief Reset internal transform information.
    */
    inline void alwaysWaitTillComplete(bool waitTillComplete)
    {   alwaysWait = waitTillComplete;    }
    /**
     \fn DGVTransform::getImageResult()
     \brief Return image result if image was passed in for transform.
    */
    DGVImage* getImageResult()
    {   return resultImage; }
    /*!
        \fn DGVTransform::setConsole(DGVConsole *newConsole)
        \brief Assigns a console for message output. You should set this before calling data members to ensure
        messages reach the console (if one is present).
	*/
	void setConsole(DGVConsole *newConsole);
	//@}

signals:
    /*!
        \fn DGVTransform::resultAvailable(DGVImage *)
        \brief Send signal that Resultant image is available for showing.
    */
    void resultAvailable(DGVImage *);
    /*!
        \fn DGVTransform::resultAvailable(Array<imageType,1> , QString)
        \brief Send signal that Resultant image is available for showing.
    */
    void resultAvailable(Array<imageType,1> , QString);
    /*!
        \fn DGVTransform::resultAvailable(Array<imageType,2> , QString)
        \brief Send signal that Resultant image is available for showing.
    */
    void resultAvailable(Array<imageType,2> , QString);
    /*!
        \fn DGVTransform::resultAvailable_1D(Array<imageType,2> , QString)
        \brief Send signal that Resultant image is available for showing. For a set of 1D data.
    */
    void resultAvailable_1D(Array<imageType,2> , QString);
    /*!
        \fn DGVTransform::resultAvailable(Array< complex<imageType>,1 > , QString)
        \brief Send signal that Resultant image is available for showing.
    */
    void resultAvailable(Array< complex<imageType>,1 > , QString);
    /*!
        \fn DGVTransform::resultAvailable(Array< complex<imageType>,2 > , QString)
        \brief Send signal that Resultant image is available for showing.
    */
    void resultAvailable(Array< complex<imageType>,2 > , QString);
    /*!
        \fn DGVTransform::resultAvailable_1D(Array< complex<imageType>,2 > , QString)
        \brief Send signal that Resultant image is available for showing. For a set of 1D data.
    */
    void resultAvailable_1D(Array< complex<imageType>,2 > , QString);

protected:
    QMutex mutex;
    QWaitCondition condition;
    bool abort;
    bool alwaysWait; //!< Always wait till the transform is done and dont run in multi-task thread.
    bool consoleAssigned; //!< Console attached?
    QString name; //!< Name of transform operation for users reference. Doesn't effect actual transforms.

    transformType transform; //!< Which transform to do so it can be run in thread.
    Array<imageType,1> *inData_1D; //!< Pointer to data to transform.
    Array<imageType,1> *outData_1D; //!< Pointer to the result of the transform.
    Array<imageType,2> *inData; //!< Pointer to data to transform.
    Array<imageType,2> *outData; //!< Pointer to the result of the transform.
    Array<complex<imageType>,1> *inComplexData_1D; //!< Pointer to complex data to transform.
    Array<complex<imageType>,1> *outComplexData_1D; //!< Pointer to the complex result of the transform.
    Array<complex<imageType>,2> *inComplexData; //!< Pointer to complex data to transform.
    Array<complex<imageType>,2> *outComplexData; //!< Pointer to the complex result of the transform.

    Array<complex<imageType>,2> fftSpace; //!< FFT Bin values for transforms
    Array<imageType,2> frtSpace; //!< FRT Bin values for transforms

    Array<complex<imageType>,1> fftSpace_1D; //!< 1D FFT Bin values for transforms
    Array<imageType,1> frtSpace_1D; //!< 1D FRT Bin values for transforms

    DGVRadonTransform<imageType> RT; //!< Radon Transforms
    DGVFourierTransform<imageType,1> Fourier_1D; //!< Fourier Transforms
    DGVFourierTransform<imageType,2> Fourier; //!< Fourier Transforms

    DGVImage *resultImage; //!< Pointer to result
    DGVConsole *console; //!< Console for message output

    /**
     \fn DGVTransform::run()
     \brief Run the transform in thread.
    */
    void run();
};



#endif // DGVTRANSFORM_H
